3.7 我怎样才能理解复杂表达式?“序列点”是什么?
序列点是一个时间点(在整个表达式全部计算完毕之后或在||、&&、?:或逗号运算符处,或在函数调用之前,此刻尘埃落定,所有的副作用都己确保结束。 ANSI/ISO C标准这样描述:
在上一个和下一个序列点之间,一个对象所保存的值至多只能被表达式的计算修改一次。而且前一个值只能用于决定将要保存的值。
第二句话比较费解,它说在一个表达式中如果某个对象需要写入,則在同一表达式中对该对象的访问应该只局限于直接用于计算将要写入的值。这条规則有效地限制了只有能确保在修改之前才访问变a的表达式为非法。例如i = i+1合法,而a[i] = i++則非法。
3.1 为什么这样的代码: a[i] = i++; 不能工作?
i左边的引用不确定,i++这样的表达式有一个副作用,会修改自身的值。由于i在同一表达式的其它地方被引用,这会导致无定义的结果。无从判断该引用(左边的a[i])是旧值还是新值。尽管在K&R中建议这类表达式的行为不确定,但C标准却强烈声明它是无定义的。
3.2 使用我的编译器,下面的代码 int i=7; printf("%d\n", i++ * i++);返回 49?不管按什么顺序计算, 难道不该打印出56吗?
尽管后缀自加和后级自减操作符++和--在输出其旧值之后才会执行运算, 但这jfd 的"之后”常常被课解,没有任何保证确保自增或自减会在输出变变原值之后和对表达式的其它部分进行计算之前立即进行。也不能保证变量的更新会在表达式“完成”(按照ANSI C的术语,在下一个“序列点”之前“之前的某个时刻进行。本例中.编泽器选择使用变量的旧值相乘以后再对二者进行自增运算。
包含多个不确定的副作用的代码的行为总是被认为末定义。(简单而言,“多
个不确定副作用”是指在同一个表达式中使用导致同一对象修改两次或修改以后又被引用的自增、自减和赋值操作符的任何组合。
3.3 对于代码 int i = 3; i = i++; 不同编译器给出不同的结果, 有的为3, 有的为 4, 哪个是正确的?
因为i++的副作用,导致未定义或非吱。
3.4 这是个巧妙的表达式: a ?= b ?= a ?= b 它不需要临时变量就可以交换 a 和 b 的值。
试图在序列点之间两次修改变量a,这是无定义的。
3.5 我可否用括号来强制执行我所需要的计算顺序?
一般来讲,不行,运算符优先级只能赋予表达式计算部分的顺序。如在下面的代码中:
f()+g()+h()
尽管我们知道乘法运算在加法之前,但这并不能说明这三个函数哪个会被首先调用。如果你需要确保子表达式的计算顺序,你可能需要使用明确的临时变量和独立的语句。
3.6 可是 && 和 || 运算符呢?我看到过类似 while((c = getchar()) !=EOF && c != ’\n’) 的代码 ……
这个运算符在此处有一个特殊的"短路”例外:如果左边的子表达式决定最终结果(即,真对于||和假对于&&)則右边的子表达式不会计算。因此,从左至右的计算可以确保。对逗表达式也是如此。而且,所有这些运算符(包括?:)都会引入一个额外的内部序列点。
3.7 我怎样才能理解复杂表达式?“序列点” 是什么?
3.8 那么, 对于 a[i] = i++; 我们不知道 a[] 的哪一个分量会被改写,但 i 的确会增加 1, 对吗?
不一定!如果一个表达式和程序变得未定义,则它的所有方面都会变成末定义。
3.9 ++i和i++有什么区别?
简单而言:++i 在i存储的值上增加一并向使用它的表达式“返回”新的、增加后的值:而i++对i 增加一,但返回原来的是木增加的值,
3.10 如果我不使用表达式的值, 我应该用 ++i 或 i++ 来自增一个变量吗?
由于这两种格式区别仅在于生成的值,所以在仅使用它们的副作用时,二者完全一样。但是,在C++中,前缀方式却是首选。
3.11 为什么如下的代码 int a = 100, b = 100; long int c = a * b; 不能工作?
根据C的内部类型转换规則,乘法是用int进行的,而其结果可能在转换为 long型并賦给左边的c之前溢出或被践短。可以使用明确的类型转换,强迫乘法以long型进行:
3.12 我需要根据条件把一个复杂的表达式赋值给两个变量中的一个。可以用下边这样的代码吗? ((condition) ? a : b) = complicated_expression;
本页共31段,2094个字符,4883 Byte(字节)